package com.example.springsecurityjwt.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;


/**
 * 因为整合了springsecurity 所以默认/login是登陆,所以我们在Controller层中不用自己写/login
 */
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * BCryptPasswordEncoder密码加密器
     * @return
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     * NoOpPasswordEncoder加密器  它就是原样输入就是不加密
     * @return
     */
    /*@Bean
    PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }*/

    /**
     *
     *  这里我们不查询数据库,在内存中模拟两个用户
     *  admin 123 这个用户有admin这个角色
     *  sang  456 这个用户有user这个角色
     *  如果这两个用户密码有加密就得注入密码加密器
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        /**
         *  我们以前写配置文件版的springsecurity的时候要配置用户登录时输入的密码要用什么加密器加密
         *  因为在注册的时候就会加密用户密码然后存到数据库，所以为了验证成功，在用户登录时传递的密码也得跟存到数据库时的加密算法一样加密一下，这样才能验证通过
         *
         *  然后我们现在是springboot整合springsecurity了，只要你再容器中注入了密码加密器的bean，用户输入的密码就自动会被这个加密器加密了
         *
         */

        //用户密码没加密，即NoOpPasswordEncoder
        /*auth.inMemoryAuthentication().withUser("admin")
                .password("123").roles("admin")
                .and()
                .withUser("sang")
                        .password("456")
                        .roles("user");*/

        //用户的密码是BCryptPasswordEncoder加密的，所以如果我们注入的加密器是加密的我们就要用这种形式
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("admin").password(new BCryptPasswordEncoder().encode("123")).roles("admin")
                .and()
                .passwordEncoder(new BCryptPasswordEncoder()).withUser("sang").password(new BCryptPasswordEncoder().encode("456")).roles("user");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .antMatchers("/hello").hasRole("user")
                .antMatchers("/admin").hasRole("admin")
                .antMatchers(HttpMethod.POST, "/login").permitAll() //post请求且url是/login的可以直接访问
                .anyRequest().authenticated();      //除以上三个之外的其他请求只要认证了就算没有角色也能访问

                //加上我们自己写的两个自定义过滤器
                http.addFilter(new JwtLoginFilter(authenticationManager()))
                .addFilter(new JwtFilter(authenticationManager()))
                .csrf().disable();

                // 禁用 SESSION、JSESSIONID
                http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}